package org.campuscontent.ui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.geom.Point2D;
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;

import org.campuscontent.io.AutomataEncoder;
import org.campuscontent.io.AutomataParser;
import org.campuscontent.model.AbstractGraph;
import org.campuscontent.model.AutomataCellViewFactory;
import org.jgraph.graph.DefaultEdge;
import org.jgraph.graph.DefaultGraphCell;
import org.jgraph.graph.DefaultGraphModel;
import org.jgraph.graph.GraphLayoutCache;
import org.jgraph.graph.GraphModel;
import org.jgraph.graph.Port;
import org.jgraph.graph.PortView;

public class AutomataEditor extends JPanel
{
	protected AutomataGraph graph;
	protected GraphModel model;
	protected String emptyGraph; 
	private boolean hasToolbar;
	
	
	public AutomataEditor(boolean wantTohasToolbar)
	{
		final GraphLayoutCache layoutCache = new GraphLayoutCache();
		layoutCache.setFactory( new AutomataCellViewFactory() );
		graph = new AutomataGraph( new DefaultGraphModel(), layoutCache );
		model = graph.getModel();
		
		hasToolbar = wantTohasToolbar;
		if (wantTohasToolbar)
		{ 
			toolbar = new AutomatToolbar();
			toolbar.setGraph( graph   );
			graph.setToolBar( toolbar );
		}
		
		
		init();
		emptyGraph = getGraphAsString();

	}

	public GraphModel getModel()
	{
		return model;
	}
	
	public void setModel(final GraphModel model)
	{
		this.model = model;
	}

	public void setEnable(final boolean enable)
	{
		graph.setEnabled(enable);
	}

	public void init()
	{
		// Use Border Layout
		setLayout( new BorderLayout() );

		// debug();
		if (hasToolbar)
		    add( toolbar, BorderLayout.NORTH );
		
		// Add the Graph as Center Component
		add( new JScrollPane(graph), BorderLayout.CENTER );
	}
	
	public AutomataGraph getGraph()
	{
		return graph;
	}
	
	public void constructGraph(final AbstractGraph abstractGraph)
	{
		final int referenceX	= 300;
		final int referenceY	= 200;
		
		int defaultX, defaultY;
		
		AutomataMarqueeHandler marqueeHandler;
		DefaultGraphCell	sNode, eNode;
		
		int cnt	= abstractGraph.getNodeCnt();
		
		for(int i = 0; i < cnt; i++)
		{
			defaultX = (int)Math.round(referenceX 	- 	180*Math.cos(360*Math.PI*i/(cnt*180)));
	        defaultY = (int)Math.round(referenceY 	- 	180*Math.sin(360*Math.PI*i/(cnt*180)));
			graph.insert(new Point2D.Double( defaultX, defaultY ), abstractGraph.getNodeLabel(i), abstractGraph.getNodeType(i));
			
		}
		
		cnt	= abstractGraph.getEdgeCnt();
		
		for(int i = 0; i < cnt; i++)
		{
			 marqueeHandler = (AutomataMarqueeHandler)graph.getMarqueeHandler();
             
			 sNode	= graph.getNodeByName(abstractGraph.getsNode(i));
			 eNode	= graph.getNodeByName(abstractGraph.geteNode(i));
			 
			 if(sNode.toString().equals(eNode.toString()))
			 {
				 final PortView portViewAt = graph.getDefaultPortForCell( sNode );
                 
                 if ( portViewAt != null )
                 {
                	 final DefaultEdge self = graph.createDefaultEdge();
                     self.getAttributes().applyMap( graph.createEdgeAttributes() );
                     self.setUserObject(abstractGraph.getEdgeLabel(i));
                     graph.getGraphLayoutCache().insertEdge( self, (Port) portViewAt.getCell(), (Port) portViewAt.getCell() );
                 }
                 
			 }
			 else
			 {
				 final PortView source = graph.getDefaultPortForCell( sNode );
				 final PortView target = graph.getDefaultPortForCell( eNode );
                     
				 marqueeHandler.connect( (Port)source.getCell(), (Port)target.getCell(), abstractGraph.getEdgeLabel(i) );
			 }
             
		}
		
		
		
	}

	public void debug()
	{
		final String filename = "C:\\workspace2\\graphpro\\config\\automata.def";

		final AutomataParser ap = AutomataParser.getInstance();
		graph = ap.getGraphFrom(filename);
	}

	public String getGraphAsString()
	{
		AutomataEncoder encoder;
		final Container parent = graph.getParent();
		String graphStr = "";
		try
		{

			final ByteArrayOutputStream bos = new ByteArrayOutputStream();
			encoder = new AutomataEncoder(new BufferedOutputStream(bos));

			encoder.writeObject(graph);
			encoder.close();

			graphStr = bos.toString();

			// uninstallListeners(graph);
			//parent.remove(graph);
		} catch (final Exception et)
		{
			JOptionPane.showMessageDialog(graph, et.getMessage(), "Error",
					JOptionPane.ERROR_MESSAGE);
		} finally
		{
			// Adds the component back into the component hierarchy
			if (parent instanceof JViewport)
			{
				final JViewport viewPort = (JViewport) parent;
				viewPort.setView(graph);
			} else
			{
				// Best effort...
				if (parent != null)
					parent.add(graph);
			}
			// And reinstalls the listener
			// installListeners(graph);
		}

		return graphStr;
	}

	public void loadGraphFromStr(final String graphStr)
	{

		//AutomatToolbar toolbar = graph.getToolBar();//BasicMarqueeHandler marqueeHandler = graph.getMarqueeHandler();
		final Container parent = graph.getParent();
		parent.remove(graph);


		try
		{

			//uninstallListeners(graph);
			if (graphStr.equals("") || graphStr.equals("empty"))
			{
//				AutomatToolbar toolbar = new AutomatToolbar();
//
//				GraphLayoutCache layoutCache = new GraphLayoutCache();
//				layoutCache.setFactory(new AutomataCellViewFactory());
//				graph = new AutomataGraph(new DefaultGraphModel(), layoutCache);
//				
//				setModel(graph.getModel());
//				toolbar.setGraph(graph);
//				graph.setToolBar(toolbar);
				
				byte[] buf = new byte[emptyGraph.length()];
				buf = emptyGraph.getBytes();
				final ByteArrayInputStream bis = new ByteArrayInputStream(buf);
				final XMLDecoder decoder = new XMLDecoder(
						new BufferedInputStream(bis));

				graph = (AutomataGraph) decoder.readObject();
				model = graph.getModel();
				if (hasToolbar)
				{
					toolbar.setGraph(graph);
					graph.setToolBar(toolbar);
				}
				
				
			} else
			{
				byte[] buf = new byte[graphStr.length()];
				buf = graphStr.getBytes();
				final ByteArrayInputStream bis = new ByteArrayInputStream(buf);
				final XMLDecoder decoder = new XMLDecoder(
						new BufferedInputStream(bis));

				graph = (AutomataGraph) decoder.readObject();
				model = graph.getModel();
				if (hasToolbar)
				{
					toolbar.setGraph(graph);
					graph.setToolBar(toolbar);
				}


				// Take the marquee handler from the original graph and
				// use it in the new graph as well.
				// graph.setMarqueeHandler(marqueeHandler);
				// Adds the component back into the component hierarchy
			}
			
			if (parent instanceof JViewport)
			{
				final JViewport viewPort = (JViewport) parent;
				viewPort.setView(graph);
			} else
			{
				// Best effort...
				parent.add(graph);
			}
			// graph.setMarqueeHandler(previousHandler);
			// And reinstalls the listener
			// installListeners(graph);
		} catch (final Exception et)
		{
			JOptionPane.showMessageDialog(graph, et.getMessage(), "Error",
					JOptionPane.ERROR_MESSAGE);
		}
	}
	
	
	//test
	public AutomataGraph getAutomataGraph()
	{
		return graph;
	}
	
	
	//test
	public AutomatToolbar getAutomatToolbar()
	{
		return toolbar;
	}
	
	protected AutomatToolbar toolbar;

	// public void loadGraphFromStr( String graphStr )
	// {
	// Container parent = graph.getParent();
	//
	// try
	// {
	// // uninstallListeners(graph);
	// parent.remove( graph );
	// if ( graphStr != null && !graphStr.equals( "" ) && !graphStr.equals(
	// "empty" ) )
	// {
	// byte[] buf = new byte[ graphStr.length() ];
	// buf = graphStr.getBytes();
	// ByteArrayInputStream bis = new ByteArrayInputStream( buf );
	// XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( bis ) );
	//
	// graph = (AutomataGraph) decoder.readObject();
	// model = graph.getModel();
	// // Take the marquee handler from the original graph and
	// // use it in the new graph as well.
	// // graph.setMarqueeHandler(marqueeHandler);
	// // Adds the component back into the component hierarchy
	// }
	//
	// if ( parent instanceof JViewport )
	// {
	// JViewport viewPort = (JViewport) parent;
	// viewPort.setView( graph );
	// }
	// else
	// {
	// // Best effort...
	// parent.add( graph );
	// }
	// // graph.setMarqueeHandler(previousHandler);
	// // And reinstalls the listener
	// // installListeners(graph);
	// }
	// catch ( Exception et )
	// {
	// JOptionPane.showMessageDialog( graph, et.getMessage(), "Error",
	// JOptionPane.ERROR_MESSAGE );
	// }
	//
	// }

}
